//-----------------------------------------------------------------------------
// Jonathan Westhues, split Nov 2006
// Modified by Greg Jones, Jan 2009
// Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011
// Modified by Christian Herrmann "iceman", 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support ISO 15693. This includes both the reader software and
// the `fake tag' modes, but at the moment I've implemented only the reader
// stuff, and that barely.
// Modified to perform modulation onboard in arm rather than on PC
// Also added additional reader commands (SELECT, READ etc.)
//-----------------------------------------------------------------------------
// The ISO 15693 describes two transmission modes from reader to tag, and 4 
// transmission modes from tag to reader. As of Mar 2010 this code only 
// supports one of each: "1of4" mode from reader to tag, and the highspeed 
// variant with one subcarrier from card to reader.
// As long, as the card fully support ISO 15693 this is no problem, since the 
// reader chooses both data rates, but some non-standard tags do not. Further for 
// the simulation to work, we will need to support all data rates.
//
// VCD (reader) -> VICC (tag)
// 1 out of 256:
// 	data rate: 1,66 kbit/s (fc/8192) 
// 	used for long range
// 1 out of 4:
// 	data rate: 26,48 kbit/s (fc/512)
//	used for short range, high speed
// 
// VICC (tag) -> VCD (reader)
// Modulation:
//		ASK / one subcarrier (423,75 khz)
//		FSK / two subcarriers (423,75 khz && 484,28 khz)
// Data Rates / Modes:
// 	low ASK: 6,62 kbit/s
// 	low FSK: 6.67 kbit/s
// 	high ASK: 26,48 kbit/s
// 	high FSK: 26,69 kbit/s
//-----------------------------------------------------------------------------
// added "1 out of 256" mode (for VCD->PICC) - atrox 20100911


// Random Remarks:
// *) UID is always used "transmission order" (LSB), which is reverse to display order

// TODO / BUGS / ISSUES:
// *) writing to tags takes longer: we miss the answer from the tag in most cases
//    -> tweak the read-timeout times
// *) signal decoding from the card is still a bit shaky. 
// *) signal decoding is unable to detect collissions.
// *) add anti-collission support for inventory-commands 
// *) read security status of a block
// *) sniffing and simulation do only support one transmission mode. need to support 
//		all 8 transmission combinations
//	*) remove or refactor code under "depricated"
// *) document all the functions

#include "proxmark3.h"
#include "util.h"
#include "apps.h"
#include "string.h"
#include "iso15693tools.h"
#include "cmd.h"

///////////////////////////////////////////////////////////////////////
// ISO 15693 Part 2 - Air Interface
// This section basicly contains transmission and receiving of bits
///////////////////////////////////////////////////////////////////////

// 32 + 2 crc + 1 
#define ISO15_MAX_FRAME		35
#define CMD_ID_RESP			5
#define CMD_READ_RESP		13
#define CMD_INV_RESP		12

#define FrameSOF              Iso15693FrameSOF
#define Logic0                Iso15693Logic0
#define Logic1                Iso15693Logic1
#define FrameEOF              Iso15693FrameEOF

#define Crc(data, len)			crc(CRC_15693, (data), (len))
#define CheckCrc(data, len)		check_crc(CRC_15693, (data), (len))
#define AddCrc(data, len)		compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)

#define sprintUID(target,uid)	Iso15693sprintUID((target), (uid))

static void BuildIdentifyRequest(uint8_t *cmdout);
//static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber );
static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid);

// ---------------------------
// Signal Processing 
// ---------------------------

// prepare data using "1 out of 4" code for later transmission
// resulting data rate is 26,48 kbit/s (fc/512)
// cmd ... data
// n ... length of data
static void CodeIso15693AsReader(uint8_t *cmd, int n) {
	int i, j;

	ToSendReset();

	// Give it a bit of slack at the beginning
	for(i = 0; i < 24; i++)
		ToSendStuffBit(1);

	// SOF for 1of4
	ToSendStuffBit(0);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(0);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	for(i = 0; i < n; i++) {
		for(j = 0; j < 8; j += 2) {
			int these = (cmd[i] >> j) & 3;
			switch(these) {
				case 0:
					ToSendStuffBit(1);
					ToSendStuffBit(0);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					break;
				case 1:
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(0);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					break;
				case 2:
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(0);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					break;
				case 3:
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(1);
					ToSendStuffBit(0);
					break;
			}
		}
	}
	// EOF
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(0);
	ToSendStuffBit(1);

	// And slack at the end, too.
	for(i = 0; i < 24; i++)
		ToSendStuffBit(1);
}

// encode data using "1 out of 256" sheme
// data rate is 1,66 kbit/s (fc/8192) 
// is designed for more robust communication over longer distances
static void CodeIso15693AsReader256(uint8_t *cmd, int n) {
	int i, j;

	ToSendReset();

	// Give it a bit of slack at the beginning
	for(i = 0; i < 24; i++)
		ToSendStuffBit(1);

	// SOF for 1of256
	ToSendStuffBit(0);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(0);
	
	for(i = 0; i < n; i++) {
		for (j = 0; j <= 255; j++) {
			if (cmd[i] == j) {
				ToSendStuffBit(1);
				ToSendStuffBit(0);
			} else {
				ToSendStuffBit(1);
				ToSendStuffBit(1);
			}			
		}	
	}
	// EOF
	ToSendStuffBit(1);
	ToSendStuffBit(1);
	ToSendStuffBit(0);
	ToSendStuffBit(1);

	// And slack at the end, too.
	for(i = 0; i < 24; i++)
		ToSendStuffBit(1);
}

// Transmit the command (to the tag) that was placed in ToSend[].
static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) {

    int c;
	volatile uint32_t r;
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);

	if (wait) {
		for (c = 0; c < *wait;) {
			if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
				AT91C_BASE_SSC->SSC_THR = 0x00;		// For exact timing!
				++c;
			}
			if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
				r = AT91C_BASE_SSC->SSC_RHR; (void)r;
			}
			WDT_HIT();
		}
	}

    c = 0;
    for(;;) {	
		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
            AT91C_BASE_SSC->SSC_THR = cmd[c];
            if( ++c >= len) break;
        }
        if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
            r = AT91C_BASE_SSC->SSC_RHR; (void)r;
        }
        WDT_HIT();		
    }
	
	if (samples) {
		if (wait)
			*samples = (c + *wait) << 3;
		else
			*samples = c << 3;	
	}
}

//-----------------------------------------------------------------------------
// Transmit the command (to the reader) that was placed in ToSend[].
//-----------------------------------------------------------------------------
static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) {
    int c = 0;
	volatile uint32_t r;
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K);
	
	if (wait) {
		for (c = 0; c < *wait;) {
			if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
				AT91C_BASE_SSC->SSC_THR = 0x00;		// For exact timing!
				++c;
			}
			if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
				r = AT91C_BASE_SSC->SSC_RHR; (void)r;
			}
			WDT_HIT();
		}
	}

    c = 0;	
    for(;;) {
		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
            AT91C_BASE_SSC->SSC_THR = cmd[c];
            if( ++c >= len) break;
        }
        if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
            r = AT91C_BASE_SSC->SSC_RHR; (void)r;
        }
        WDT_HIT();		
    }
	if (samples) {
		if (wait)
			*samples = (c + *wait) << 3;
		else
			*samples = c << 3;	
	}
}

//-----------------------------------------------------------------------------
// DEMODULATE tag answer
//-----------------------------------------------------------------------------
static int DemodAnswer(uint8_t *received, uint8_t *dest, uint16_t samplecount) {
	
	int i, j;
	int max = 0, maxPos = 0, skip = 4;
	int k = 0; // this will be our return value

	// First, correlate for SOF
	for (i = 0; i < samplecount; i++) {
		int corr = 0;
		for ( j = 0; j < ARRAYLEN(FrameSOF); j += skip) {
			corr += FrameSOF[j] * dest[i+(j/skip)];
		}
		if (corr > max) {
			max = corr;
			maxPos = i;
		}
	}
	//	DbpString("SOF at %d, correlation %d", maxPos,max/(ARRAYLEN(FrameSOF)/skip));

	// greg - If correlation is less than 1 then there's little point in continuing
	if ((max / (ARRAYLEN(FrameSOF)/skip) ) < 1) 
		return k;
	
	i = maxPos + ARRAYLEN(FrameSOF) / skip;

	uint8_t outBuf[ISO15_MAX_FRAME];
	memset(outBuf, 0, sizeof(outBuf));
	uint8_t mask = 0x01;
	for(;;) {
		int corr0 = 0, corr1 = 0, corrEOF = 0;
		for (j = 0; j < ARRAYLEN(Logic0); j += skip) {
			corr0 += Logic0[j] * dest[i+(j/skip)];
		}
		for (j = 0; j < ARRAYLEN(Logic1); j += skip) {
			corr1 += Logic1[j] * dest[i+(j/skip)];
		}
		for (j = 0; j < ARRAYLEN(FrameEOF); j += skip) {
			corrEOF += FrameEOF[j] * dest[i+(j/skip)];
		}
		// Even things out by the length of the target waveform.
		corr0 *= 4;
		corr1 *= 4;
		// if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
			// Dbprintf("Corr1 %d, Corr0 %d, CorrEOF %d", corr1, corr0, corrEOF);

		if (corrEOF > corr1 && corrEOF > corr0)
			break;
		
		if (corr1 > corr0) {
			i += ARRAYLEN(Logic1) / skip;
			outBuf[k] |= mask;
		} else {
			i += ARRAYLEN(Logic0) / skip;
		}
		
		mask <<= 1;
		
		if (mask == 0) {
			k++;
			mask = 0x01;
		}
		
		if ( ( i + (int)ARRAYLEN(FrameEOF)) >= samplecount-1) {
			//Dbprintf("[!] ran off end!  %d | %d",( i + (int)ARRAYLEN(FrameEOF)), samplecount-1);
			break;
		}
	}
	
	if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("ice: demod bytes %u", k);
			
	if (mask != 0x01) { // this happens, when we miss the EOF
		
		// TODO: for some reason this happens quite often
		if (MF_DBGLEVEL >= MF_DBG_ERROR && k != 0) Dbprintf("[!] error, uneven octet! (extra bits!) mask %02x", mask);
		//if (mask < 0x08) k--; // discard the last uneven octet;
		// 0x08 is an assumption - but works quite often
	}

	for(i = 0; i < k; i++)
		received[i] = outBuf[i];

	// return the number of bytes demodulated
	return k;
}

// Read from Tag
// Parameters:
//		received
//		samples
//		elapsed
// returns: 
//		number of decoded bytes
// logging enabled
static int GetIso15693AnswerFromTag(uint8_t *received, int *elapsed) {

#define SIGNAL_BUFF_SIZE 15000
	// get current clock
	uint32_t time_0 = GetCountSspClk();
	uint32_t time_stop = 0;
	bool getNext = false;
	int counter = 0, ci = 0, cq = 0;
	//volatile uint32_t r;
	uint8_t *buf = BigBuf_malloc(SIGNAL_BUFF_SIZE);

	if (elapsed) *elapsed = 0;
	
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
		
	// for (counter = 0; counter < wait;) {
		
		// WDT_HIT();

		// if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
			// AT91C_BASE_SSC->SSC_THR = 0x00;		// For exact timing!
			// counter++;
		// }
		// if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
			 // r = AT91C_BASE_SSC->SSC_RHR; (void)r;
		// }
	// }
	// counter = 0;


	for(;;) {
		WDT_HIT();

		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
			AT91C_BASE_SSC->SSC_THR = 0x00; //0x43;
			// To make use of exact timing of next command from reader!!
			if (elapsed) (*elapsed)++;
		}
		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {

			ci = (int8_t)AT91C_BASE_SSC->SSC_RHR;
			
			// LSB is a FPGA singal bit
			ci >>= 1;			
			ci = ABS(ci);

			// The samples are correlations against I and Q versions of the
			// tone that the tag AM-modulates, so every other sample is I,
			// every other is Q. We just want power, so abs(I) + abs(Q) is
			// close to what we want.
			// iceman 2016, amplitude sqrt(abs(i) + abs(q))
			if (getNext) {
								
				buf[counter++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1));
				
				if (counter >= SIGNAL_BUFF_SIZE)
					break;
			} else {
				cq = ci;
			}
			getNext = !getNext;
		}
	}	
	time_stop = GetCountSspClk() - time_0 ;	
	int len = DemodAnswer(received, buf, counter);	
	LogTrace(received, len, time_0 << 4, time_stop << 4, NULL, false);
	BigBuf_free();	
	return len;
}


// Now the GetISO15693 message from sniffing command
// logging enable,
static int GetIso15693AnswerFromSniff(uint8_t *received, int *samples, int *elapsed) {

	bool getNext = false;
	int counter = 0, ci = 0, cq = 0;
	uint32_t time_0 = 0, time_stop = 0;
	uint8_t *buf = BigBuf_get_addr();

	// get current clock
	time_0 = GetCountSspClk();
		
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
	
	for(;;) {
		WDT_HIT();

		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))
			AT91C_BASE_SSC->SSC_THR = 0x43;

		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {

			ci = (int8_t)AT91C_BASE_SSC->SSC_RHR;
			
			// LSB is a FPGA singal bit
			ci >>= 1;			
			ci = ABS(ci);
			
			// The samples are correlations against I and Q versions of the
			// tone that the tag AM-modulates, so every other sample is I,
			// every other is Q. We just want power, so abs(I) + abs(Q) is
			// close to what we want.
			if (getNext) {

				buf[counter++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1));

				if(counter >= 20000)
					break;
			} else {
				 cq = ci;
			}
			getNext = !getNext;
		}
	}
	
	time_stop = GetCountSspClk() - time_0;
	int k = DemodAnswer(received, buf, counter);	
	LogTrace(received, k, time_0 << 4, time_stop << 4, NULL, false);	
	return k;	
}

//-----------------------------------------------------------------------------
// Start to read an ISO 15693 tag. We send an identify request, then wait
// for the response. The response is not demodulated, just left in the buffer
// so that it can be downloaded to a PC and processed there.
//-----------------------------------------------------------------------------
void AcquireRawAdcSamplesIso15693(void) {
	int c = 0, getNext = false;
	volatile uint32_t r;
	int ci = 0, cq = 0;
	
	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
	SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
	FpgaSetupSsc();
	// Give the tags time to energize
	//FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
	
	// Now send the command
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
	SpinDelay(200);

	uint8_t *buf = BigBuf_get_addr();
	
	uint32_t time_start = GetCountSspClk();
	uint8_t cmd[CMD_ID_RESP] = {0};
	BuildIdentifyRequest(cmd);
	
	// sending command
	c = 0;
	for(;;) {
		WDT_HIT();
		
		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
			AT91C_BASE_SSC->SSC_THR = ToSend[c];
			c++;
			if(c == ToSendMax + 3) {
				break;
			}
		}
		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
			r = AT91C_BASE_SSC->SSC_RHR; (void)r;
		}
	}

	
	LogTrace(cmd, CMD_ID_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true);
	
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);

	c = 0;
	for(;;) {
		WDT_HIT();
		
		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))
			AT91C_BASE_SSC->SSC_THR = 0x43;
		
		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {

			ci = (int8_t)AT91C_BASE_SSC->SSC_RHR;

			// LSB is a FPGA singal bit
			ci >>= 1;
			
			ci = ABS(ci);
			
			// The samples are correlations against I and Q versions of the
			// tone that the tag AM-modulates, so every other sample is I,
			// every other is Q. We just want power, so abs(I) + abs(Q) is
			// close to what we want.
			// iceman 2016, amplitude sqrt(abs(i) + abs(q))
			if (getNext) {
				
				buf[c++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1));
				
				if (c >= 7000) break;
				
			} else {
				cq = ci;
			}
			getNext = !getNext;
		}
	}
}

// switch_off,  initreader, no logging
void RecordRawAdcSamplesIso15693(void) {

	int c = 0, getNext = false;
	int ci = 0, cq = 0;
	
	Iso15693InitReader();

	uint8_t *buf = BigBuf_get_addr();

	for(;;) { 
		WDT_HIT();
		
		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
			AT91C_BASE_SSC->SSC_THR = 0x43;
		}
		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {

			ci = (int8_t)AT91C_BASE_SSC->SSC_RHR;
			
			// LSB is a FPGA singal bit
			ci >>= 1;
			
			ci = ABS(ci);
			// The samples are correlations against I and Q versions of the
			// tone that the tag AM-modulates, so every other sample is I,
			// every other is Q. We just want power, so abs(I) + abs(Q) is
			// close to what we want.
			if (getNext) {
				
				buf[c++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1));

				if(c >= 7000)
					break;
			} else {
				cq = ci;
			}

			getNext = !getNext;
		}
	}
	
	Dbprintf("done");
	switch_off();
}

// Initialize the proxmark as iso15k reader 
// (this might produces glitches that confuse some tags
void Iso15693InitReader(void) {
	LEDsoff();
	clear_trace();
	set_tracing(true);
	
	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);

	// Start from off (no field generated)
	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
	SpinDelay(10);

	SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
	
	FpgaSetupSsc();

	// Give the tags time to energize
	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
	SpinDelay(200);
	
	// Start the timer
	StartCountSspClk();
	
	if (MF_DBGLEVEL >= MF_DBG_EXTENDED ) DbpString("[+] Iso15693InitReader Exit");

	LED_A_ON();
}

///////////////////////////////////////////////////////////////////////
// ISO 15693 Part 3 - Air Interface
// This section basicly contains transmission and receiving of bits
///////////////////////////////////////////////////////////////////////

// Encode (into the ToSend buffers) an identify request, which is the first
// thing that you must send to a tag to get a response.
static void BuildIdentifyRequest(uint8_t *out) {

	uint8_t cmd[CMD_ID_RESP] = {0, ISO15_CMD_INVENTORY, 0, 0, 0};
	// flags
	cmd[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
	// no mask
	cmd[2] = 0x00;
	// CRC
	AddCrc(cmd, 3);
	// coding as high speed (1 out of 4)
	CodeIso15693AsReader(cmd, CMD_ID_RESP);
	memcpy(out, cmd, CMD_ID_RESP);
}

// uid is in transmission order (which is reverse of display order)
/*
static void BuildReadBlockRequest(uint8_t **out, uint8_t *uid, uint8_t blockNumber ) {
	uint8_t cmd[CMD_READ_RESP] = {0,0,0,0,0,0,0,0,0,0,0,0,0};
	// If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
	// followed by teh block data
	// one sub-carrier, inventory, 1 slot, fast rate
	cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit
	// READ BLOCK command code
	cmd[1] = 0x20;
	// UID may be optionally specified here
	// 64-bit UID
	cmd[2] = uid[0];
	cmd[3] = uid[1];
	cmd[4] = uid[2];
	cmd[5] = uid[3];
	cmd[6] = uid[4];
	cmd[7] = uid[5];
	cmd[8] = uid[6];
	cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique)
	// Block number to read
	cmd[10] = blockNumber;//0x00;
	// CRC
	AddCrc(cmd, 11);
	CodeIso15693AsReader(cmd, CMD_READ_RESP);
	memcpy(out, cmd, CMD_ID_RESP);
}
*/

// Now the VICC>VCD responses when we are simulating a tag
static void BuildInventoryResponse(uint8_t *out, uint8_t *uid) {

	uint8_t cmd[CMD_INV_RESP] = {0,0,0,0,0,0,0,0,0,0,0,0};

	// one sub-carrier, inventory, 1 slot, fast rate
	// AFI is at bit 5 (1<<4) when doing an INVENTORY
    //(1 << 2) | (1 << 5) | (1 << 1);
	cmd[0] = 0; // 
	cmd[1] = 0; // DSFID (data storage format identifier).  0x00 = not supported
	// 64-bit UID
	cmd[2] = uid[7]; //0x32;
	cmd[3] = uid[6]; //0x4b;
	cmd[4] = uid[5]; //0x03;
	cmd[5] = uid[4]; //0x01;
	cmd[6] = uid[3]; //0x00;
	cmd[7] = uid[2]; //0x10;
	cmd[8] = uid[1]; //0x05;
	cmd[9] = uid[0]; //0xe0;
	// CRC
	AddCrc(cmd, 10);
	CodeIso15693AsReader(cmd, CMD_INV_RESP);
	memcpy(out, cmd, CMD_ID_RESP);
}

// Universal Method for sending to and recv bytes from a tag
// 	init ... should we initialize the reader?
// 	speed ... 0 low speed, 1 hi speed 
// 	**recv will return you a pointer to the received data
// 	If you do not need the answer use NULL for *recv[] 
//	return: lenght of received data
// logging enabled
int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *outdata) {

	int t_samples = 0, wait = 0, elapsed = 0, answer_len = 0;
	
	LEDsoff();
	
	if (init) Iso15693InitReader();
		
	LED_A_ON();

	if (!speed)
		CodeIso15693AsReader256(send, sendlen); // low speed (1 out of 256)
	else
		CodeIso15693AsReader(send, sendlen);	// high speed (1 out of 4)

	LED_A_INV();
	
	uint32_t time_start = GetCountSspClk();

	TransmitTo15693Tag(ToSend, ToSendMax, &t_samples, &wait);
	LogTrace(send, sendlen, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true);
	
	// Now wait for a response
	if (outdata != NULL) {
		LED_B_INV();		
		answer_len = GetIso15693AnswerFromTag(outdata, &elapsed);
	}

	LEDsoff();
	return answer_len;
}

// --------------------------------------------------------------------
// Debug Functions 
// --------------------------------------------------------------------

// Decodes a message from a tag and displays its metadata and content
#define DBD15STATLEN 48
void DbdecodeIso15693Answer(int len, uint8_t *d) {
	char status[DBD15STATLEN+1] = {0};

	if (len > 3) {
		if (d[0] & ( 1 << 3 )) 
			strncat(status, "ProtExt ", DBD15STATLEN);
		if (d[0] & 1) { 
			// error
			strncat(status, "Error ", DBD15STATLEN);
			switch (d[1]) {
				case 0x01: 
					strncat(status, "01: not supported", DBD15STATLEN);
					break;
				case 0x02: 
					strncat(status, "02: not recognized", DBD15STATLEN);
					break;
				case 0x03: 
					strncat(status, "03: opt not supported", DBD15STATLEN);
					break;
				case 0x0f: 
					strncat(status, "0F: no info", DBD15STATLEN);
					break;
				case 0x10: 
					strncat(status, "10: dont exist", DBD15STATLEN);
					break;
				case 0x11: 
					strncat(status, "11: lock again", DBD15STATLEN);
					break;
				case 0x12: 
					strncat(status, "12: locked", DBD15STATLEN);
					break;
				case 0x13: 
					strncat(status, "13: program error", DBD15STATLEN);
					break;
				case 0x14: 
					strncat(status, "14: lock error", DBD15STATLEN);
					break;
				default:
					strncat(status, "unknown error", DBD15STATLEN);
			}
			strncat(status ," " ,DBD15STATLEN);
		} else {
			strncat(status ,"No error ", DBD15STATLEN);
		}
			
		if (CheckCrc(d, len))
			strncat(status, "[+] crc OK", DBD15STATLEN);
		else
			strncat(status, "[!] crc fail", DBD15STATLEN);

		if ( MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("%s", status);
	}
}

///////////////////////////////////////////////////////////////////////
// Functions called via USB/Client
///////////////////////////////////////////////////////////////////////

//-----------------------------------------------------------------------------
// Act as ISO15693 reader, perform anti-collision and then attempt to read a sector
// all demodulation performed in arm rather than host. - greg
//-----------------------------------------------------------------------------
// ok
// parameter is unused !?!
void ReaderIso15693(uint32_t parameter) {
	int answerLen1 = 0;
	//int answerLen2 = 0;
	//int answerLen3 = 0;
	int tsamples = 0, wait = 0, elapsed = 0;
	
	uint8_t uid[8] = {0,0,0,0,0,0,0,0};

	// set up device/fpga 
	Iso15693InitReader();
	
	uint8_t *answer1 = BigBuf_malloc(50);
	uint8_t *answer2 = BigBuf_malloc(50);
	//uint8_t *answer3 = BigBuf_malloc(50);
	// Blank arrays
	memset(answer1, 0x00, 50);
	memset(answer2, 0x00, 50);
	//memset(answer3, 0x00, 50);

	// Now send the IDENTIFY command
	// FIRST WE RUN AN INVENTORY TO GET THE TAG UID
	// THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME
	uint32_t time_start = GetCountSspClk();
	uint8_t cmd[CMD_ID_RESP] = {0};
	BuildIdentifyRequest( cmd );
	TransmitTo15693Tag(ToSend, ToSendMax, &tsamples, &wait);
	LogTrace(cmd, CMD_ID_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true);
		
	// Now wait for a response
	answerLen1 = GetIso15693AnswerFromTag(answer1, &elapsed) ;

	// we should do a better check than this
	if (answerLen1 >= 12) {
		uid[0] = answer1[9]; // always E0
		uid[1] = answer1[8]; // IC Manufacturer code
		uid[2] = answer1[7];
		uid[3] = answer1[6];
		uid[4] = answer1[5];
		uid[5] = answer1[4];
		uid[6] = answer1[3]; 
		uid[7] = answer1[2];
	
		if ( MF_DBGLEVEL >= MF_DBG_EXTENDED) {	
			Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X",
				uid[0], uid[1], uid[2], uid[3],
				uid[4], uid[5], uid[5], uid[6]
			);
		}
		// send UID back to client.
		// arg0 = 1 = OK
		// arg1 = len of response (12 bytes)
		// arg2 = rtf
		// asbytes = uid.
		cmd_send(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid));
	}

	if ( MF_DBGLEVEL >= MF_DBG_EXTENDED) {
		Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen1);
		DbdecodeIso15693Answer(answerLen1, answer1);
		Dbhexdump(answerLen1, answer1, true);
	}

	// DEBUG read all pages
/*
	if (answerLen1 >= 12 && MF_DBGLEVEL >= MF_DBG_EXTENDED) {
		i = 0;			
		while ( i < 32 ) {  // sanity check, assume max 32 pages
			
			cmdlen = BuildReadBlockRequest(cmd, uid, i);
				
			TransmitTo15693Tag(ToSend, ToSendMax, &tsamples, &wait); 
			LogTrace(cmd, cmdlen, time_start<<4, (GetCountSspClk()-time_start)<<4, NULL, true);	
			
			answerLen2 = GetIso15693AnswerFromTag(answer2, &elapsed);
			if (answerLen2 > 0) {
				Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen2);
				DbdecodeIso15693Answer(answerLen2, answer2);
				Dbhexdump(answerLen2, answer2, true);
				if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr 
			} 
			i++;
		} 
	}
*/
	switch_off();
}

// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
// all demodulation performed in arm rather than host. - greg
void SimTagIso15693(uint32_t parameter, uint8_t *uid) {
	
	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);	
	SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
	FpgaSetupSsc();
	// Start from off (no field generated)
    FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
	SpinDelay(200);
	
	LED_A_ON();

	uint32_t time_start = 0;
	int ans = 0, samples = 0, tsamples = 0;
	int wait = 0, elapsed = 0;

	Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]);

	uint8_t buf[ISO15_MAX_FRAME];
	memset(buf, 0x00, sizeof(buf));

	LED_C_ON();

	// Build a suitable reponse to the reader INVENTORY cocmmand
	// not so obsvious, but in the call to BuildInventoryResponse,  the command is copied to the global ToSend buffer used below.			
	uint8_t cmd[CMD_INV_RESP] = {0};
	BuildInventoryResponse(cmd, uid);
	
	while (!BUTTON_PRESS() && !usb_poll_validate_length() ) {
		WDT_HIT();
	
		// Listen to reader
		ans = GetIso15693AnswerFromSniff(buf, &samples, &elapsed) ;

		// we should do a better check than this
		if (ans >= 1 ) {
						
			time_start = GetCountSspClk();
			TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait);
			LogTrace(cmd, CMD_INV_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true);						
					
			if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
				Dbprintf("[+] %d octets read from reader command: %x %x %x %x %x %x %x %x", ans,
					buf[0], buf[1], buf[2],	buf[3],
					buf[4], buf[5],	buf[6], buf[7]
				);
			}
		}
	}
	switch_off();
}

// Since there is no standardized way of reading the AFI out of a tag, we will brute force it
// (some manufactures offer a way to read the AFI, though)
void BruteforceIso15693Afi(uint32_t speed) {	

	uint8_t data[7] = {0,0,0,0,0,0,0};
	uint8_t buf[ISO15_MAX_FRAME];
	memset(buf, 0x00, sizeof(buf));
	int datalen = 0, recvlen = 0;
	
	Iso15693InitReader();
	
	// first without AFI
	// Tags should respond wihtout AFI and with AFI=0 even when AFI is active
	
	data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
	data[1] = ISO15_CMD_INVENTORY;
	data[2] = 0; // mask length
	AddCrc(data, 3);
	datalen += 2;
	
	recvlen = SendDataTag(data, datalen, false, speed, buf);
	
	WDT_HIT();
	
	if (recvlen >= 12) {
		Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2) );
	}
	
	// now with AFI
	data[0] |= ISO15_REQINV_AFI;
	//data[1] = ISO15_CMD_INVENTORY;
	data[2] = 0; // AFI
	data[3] = 0; // mask length
	
	for (uint16_t i = 0; i < 256; i++) {
		data[2] = i & 0xFF;
		AddCrc(data, 4);
		datalen += 2;
		recvlen = SendDataTag(data, datalen, false, speed, buf);
		WDT_HIT();
		if (recvlen >= 12) {
			Dbprintf("AFI = %i  UID = %s", i, sprintUID(NULL, buf + 2) );
		}
		
		if (BUTTON_PRESS()) {
			DbpString("button pressed, aborting..");
			break;
		}
	}	
	
	DbpString("AFI Bruteforcing done.");
	switch_off();
}

// Allows to directly send commands to the tag via the client
// Has to increase dialog between device and client. 
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) {

	bool init = true;
	int buflen = 0;
	uint8_t buf[ISO15_MAX_FRAME];
	memset(buf, 0x00, sizeof(buf));

	if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
		DbpString("[+] SEND");
		Dbhexdump(datalen, data, true);
	}
	
	buflen = SendDataTag(data, datalen, init, speed, (recv ? buf : NULL));
	
	if (recv) { 
		buflen = (buflen > ISO15_MAX_FRAME) ? ISO15_MAX_FRAME : buflen;
		
		LED_B_ON();
		cmd_send(CMD_ACK, buflen, 0, 0, buf, buflen);
		LED_B_OFF();	
		
		if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
			DbpString("[+] RECV");
			DbdecodeIso15693Answer(buflen, buf);
			Dbhexdump(buflen, buf, true);
		}
	} else {
		cmd_send(CMD_ACK,1,0,0,0,0);
	}
}